package com.cxb.java;

/**
 * @Classname VisibilityTest
 * @Date 2023/4/12 21:30
 * @Created by Administrator
 * @Description TODO
 */

/**
 * 可见性问题深入分析
 * -XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly -Xcomp
 * hsdis-amd64.dll
 */
public class VisibilityTest {
    // storeLoad JVM内存屏障 ------> (汇编层面指令) lock; addl $0,0(%%rsp)
    // lock前缀指令不是内存屏障的指令 但是有内存屏障的效果  缓存失效
    // private volatile boolean flag = true;
    private volatile boolean flag = true;
    // private volatile int count = 0;
    // private Integer count = 0;
    private int count = 0;

    public void refresh() {
        flag = false;
        System.out.println(Thread.currentThread().getName() + "修改flag:" + flag);
    }

    public void load() {
        System.out.println(Thread.currentThread().getName() + "开始执行......");
        while (flag) {
            //TODO 业务逻辑
            count++;
            //JMM(Java Memory Model)模型  内存模型: 线程间通信有关  共享内存模型
            //可见性方式如下
            //1.flag变量前加volatile关键字 可以跳出循环 storeLoad
            // JVM内存屏障(汇编层面指令)  lock; addl $0, $0(%rsp)
            // lock前缀指令不是内存屏障的指令,但是有内存屏障的效果 缓存失效  通过内存屏障实现的
            //2.UnsafeFactory.getUnsafe().stoteFence(); 内存屏障 也可也可以跳出循环
            // UnsafeFactory.getUnsafe().stoteFence();
            //3.Thread.yield(); 可以跳出循环  释放时间片 上下文切换  加载上下文 flag=true
            //4.System.out.println(count); println底层由synchronized实现 也是内存屏障 也可以跳出循环
            //System.out.println(count);
            //5.LockSupport.unpark(Thread.currentThread()); 可以跳出循环
            //LockSupport.unpark(Thread.currentThread());
            //6.count变量前加volatile关键字 可以跳出循环
            //7.private Integer count = 0; 可以跳出循环

            //8.showWaite(1000000);//1ms  缓存数据被清理淘汰了(过期了)      可以跳出循环
            //showWaite(1000); //1微秒  缓存数据还在不会淘汰 时间太短 不可以跳出循环
            //Thread.sleep()也是通过内存屏障
//            try {
//                Thread.sleep(1000);
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }

            // 总结： java中可见性如何保证？ 方式归类有两种：
            //1.jvm层面 storeLoad内存屏障  ===> x86  lock替代了mfence
            //2.上下文切换 Thread.yield();
        }
        System.out.println(Thread.currentThread().getName() + "跳出循环count:" + count);
    }

    public static void main(String[] args) throws InterruptedException {
        VisibilityTest test = new VisibilityTest();
        Thread t1 = new Thread(() -> test.load(), "t1");
        t1.start();

        Thread.sleep(1000);

        Thread t2 = new Thread(() -> test.refresh(), "t2");
        t2.start();
    }

    public static void showWaite(long interval) {
        long start = System.nanoTime();
        long end;
        do {
            end = System.nanoTime();
        } while (interval + start >= end);
    }
}
